package g6.UddiRegistration;

import java.rmi.RemoteException;
import java.util.List;

import org.uddi.api_v3.AccessPoint;
import org.uddi.api_v3.AuthToken;
import org.uddi.api_v3.BindingDetail;
import org.uddi.api_v3.BindingTemplate;
import org.uddi.api_v3.BindingTemplates;
import org.uddi.api_v3.BusinessDetail;
import org.uddi.api_v3.BusinessEntity;
import org.uddi.api_v3.BusinessInfo;
import org.uddi.api_v3.BusinessList;
import org.uddi.api_v3.BusinessService;
import org.uddi.api_v3.BusinessServices;
import org.uddi.api_v3.CategoryBag;
import org.uddi.api_v3.DeleteBusiness;
import org.uddi.api_v3.Description;
import org.uddi.api_v3.GetBusinessDetail;
import org.uddi.api_v3.IdentifierBag;
import org.uddi.api_v3.InstanceDetails;
import org.uddi.api_v3.KeyedReference;
import org.uddi.api_v3.Name;
import org.uddi.api_v3.OverviewDoc;
import org.uddi.api_v3.OverviewURL;
import org.uddi.api_v3.SaveBinding;
import org.uddi.api_v3.SaveBusiness;
import org.uddi.api_v3.SaveService;
import org.uddi.api_v3.SaveTModel;
import org.uddi.api_v3.ServiceDetail;
import org.uddi.api_v3.TModel;
import org.uddi.api_v3.TModelDetail;
import org.uddi.api_v3.TModelInstanceDetails;
import org.uddi.api_v3.TModelInstanceInfo;
import org.uddi.v3_service.DispositionReportFaultMessage;
import org.uddi.v3_service.UDDIPublicationPortType;

public class JuddiPublisher {
	private AuthToken myPubAuthToken;
	private UDDIPublicationPortType myPublicationPortType;
		
	public JuddiPublisher(UDDIPublicationPortType publicationPortType, AuthToken authToken) {
		this.myPubAuthToken = authToken;
		this.myPublicationPortType = publicationPortType;
	}
	
	public void deleteBusinessEntity(BusinessList businessList) throws DispositionReportFaultMessage, RemoteException {
		int size = businessList.getBusinessInfos().getBusinessInfo().size();
		for (int i = 0; i < size; i++) {				
			BusinessInfo info = businessList.getBusinessInfos().getBusinessInfo().get(i);
			DeleteBusiness db = new DeleteBusiness();
			db.getBusinessKey().add(info.getBusinessKey());
			db.setAuthInfo(this.myPubAuthToken.getAuthInfo());		
			this.myPublicationPortType.deleteBusiness(db);
			System.out.println("Business deleted");
		}
	}
	
	public String createBusinessEntity(String businessName, String descriptionText) throws DispositionReportFaultMessage, RemoteException{
		 // Creating the parent business entity that will contain our service.		
		BusinessEntity businessEntity = new BusinessEntity();
		Name myBusName = new Name();
		myBusName.setValue(businessName);
		businessEntity.getName().add(myBusName);
		
		Description description = new Description();
		description.setValue(descriptionText);
		businessEntity.getDescription().add(description);
				
		// Adding the business entity to the "save" structure, using our publisher's authentication info and saving away.
		SaveBusiness sb = new SaveBusiness();
		sb.getBusinessEntity().add(businessEntity);
		sb.setAuthInfo(this.myPubAuthToken.getAuthInfo());
		
		//Business Detail
		BusinessDetail bd = myPublicationPortType.saveBusiness(sb);
		String businessKey = bd.getBusinessEntity().get(0).getBusinessKey();
		String name = bd.getBusinessEntity().get(0).getName().get(0).getValue();
		System.out.println("Business created with key:  " + businessKey + " " + name);	
		return businessKey;
	}
	
	public void createBusinessService(BusinessEntity businessEntity, String businessServiceName, String url, String descriptionValue, String uri, String modelNameValue, String modelDetails) throws DispositionReportFaultMessage, RemoteException {		
		BusinessService myService = new BusinessService();		
		myService.setBusinessKey(businessEntity.getBusinessKey());
		
		Name myServName = new Name();
		myServName.setValue(businessServiceName);
	    myService.getName().add(myServName);
	 
	    Description description = new Description();
	    description.setValue(descriptionValue);
	    myService.getDescription().add(description);
	    
	    if (businessEntity.getBusinessServices() == null){
	    	BusinessServices businessServices = new BusinessServices();
	    	businessEntity.setBusinessServices(businessServices);
	    }
	    //List<BusinessService> bslist = businessServices.getBusinessService();
	    List<BusinessService> bslist =  businessEntity.getBusinessServices().getBusinessService();
	    bslist.add(myService);
	    
		 
		// Adding the service to the "save" structure, using our publisher's authentication info and saving away.
		SaveService ss = new SaveService();
		ss.getBusinessService().add(myService);
		ss.setAuthInfo(this.myPubAuthToken.getAuthInfo());
		
		//Service Detail
		ServiceDetail sd = this.myPublicationPortType.saveService(ss);
		String myServKey = sd.getBusinessService().get(0).getServiceKey();
		System.out.println("Service with key:  " + myServKey +  " was published.");
		 
	    // Add binding templates
	    BindingTemplates templates = new BindingTemplates();
	    myService.setBindingTemplates(templates);
	 
	    BindingTemplate myTemplate = new BindingTemplate();
	    myTemplate.setServiceKey(myServKey);
	 
	    AccessPoint accessPoint = createAccessPoint(url);
	    myTemplate.setAccessPoint(accessPoint);
	 	
	    templates.getBindingTemplate().add(myTemplate);
	     
	    //Add TModel
	    /**
	     * This creates the unique, well-defined tModel representing the service's WSDL
	     */
	    TModelDetail tModelDetail = publishWSDL_tModel(url, myPubAuthToken.getAuthInfo(), modelNameValue, businessServiceName, descriptionValue);
	    List<TModel> tModelList = tModelDetail.getTModel(); 
		 
		TModelInstanceDetails tModelInstanceDetails = new TModelInstanceDetails();
		List<TModelInstanceInfo> tModelInstanceInfoList = tModelInstanceDetails.getTModelInstanceInfo();
		 
		for(TModel tm: tModelList) {
			TModelInstanceInfo tModelInstanceInfo = new TModelInstanceInfo();
			tModelInstanceInfoList.add(tModelInstanceInfo);
			tModelInstanceInfo.setTModelKey(tm.getTModelKey());
			InstanceDetails instanceDetails = new InstanceDetails();
			instanceDetails.setInstanceParms(modelDetails);
			tModelInstanceInfo.setInstanceDetails(instanceDetails); 
		}		    

	    /**
	     * Associate the set of tModels with the Service's BindingTemplate
	     */
	    myTemplate.setTModelInstanceDetails(tModelInstanceDetails);
		 
	    //set CategoryBag
	    myTemplate.setCategoryBag(tModelList.get(0).getCategoryBag());
	    
	    // Adding the binding to the "save" structure, using our publisher's authentication info and saving away.
	    SaveBinding sbinding = new SaveBinding();
	    sbinding.getBindingTemplate().add(myTemplate);
	    sbinding.setAuthInfo(myPubAuthToken.getAuthInfo());
	    BindingDetail binddetail = this.myPublicationPortType.saveBinding(sbinding); 
	    System.out.println("My binding key:  " + binddetail.getBindingTemplate().get(0).getBindingKey());	
		   
	    //update the service to the "save" structure, using our publisher's authentication info and saving away.
	    SaveService updates = new SaveService();
	    myService.setServiceKey(myServKey);
	    updates.getBusinessService().add(myService);
	    updates.setAuthInfo(myPubAuthToken.getAuthInfo());
	    sd = this.myPublicationPortType.saveService(updates);
	    myServKey = sd.getBusinessService().get(0).getServiceKey();
	    System.out.println("Updated service with key:  " + myServKey);		
	}

    /**
       * Creates a tModel, identifying WSDL endpoint. This is the
       * best practices model for registering a WSDL describing a business service.
       * Applications searching registries for WSDL will be searching registries for
       * this data structure.
       *
       * The data structure contains an endpoint for the Service's WSDL document, so
       * each service will need a unique tModel.
       *
       * Best Practices are outlined in the document
       * http://www.oasis-open.org/committees/uddi-spec/doc/bp/uddi-spec-tc-bp-using-wsdl-v108-20021110.htm
     * @throws RemoteException 
     * @throws DispositionReportFaultMessage 
       *
       */
	private TModelDetail publishWSDL_tModel(String url, String authinfo, String modelNameValue, String serviceName, String serviceDescription) throws DispositionReportFaultMessage, RemoteException {
		TModel tModel = new TModel();
		 
		//set the name of tModel
		Name tModelName = new Name();
		tModelName.setLang("en");
		tModelName.setValue(modelNameValue);
		tModel.setName(tModelName);		 
		tModel.setDeleted(false);
		 
		//set Overview Docs
		OverviewDoc overviewDoc = new OverviewDoc();
		OverviewURL overviewurl = new OverviewURL();
		overviewurl.setUseType("WSDL source document");
		overviewurl.setValue(url);     
		overviewDoc.setOverviewURL(overviewurl);     
		List<OverviewDoc> overviewdoclist = tModel.getOverviewDoc();
		overviewdoclist.add(overviewDoc);  
		
		TModelDetail tModelDetail = new TModelDetail();
		List<TModel> tModelList = tModelDetail.getTModel();
		tModelList.add(tModel); 
		 
		//Adding the tModel to the "save" structure, using our publisher's authentication info and saving away.
		SaveTModel saveTModel = new SaveTModel();
		saveTModel.getTModel().addAll(tModelList);
		saveTModel.setAuthInfo(authinfo);
		tModelDetail = this.myPublicationPortType.saveTModel(saveTModel);
		   
		String tModelKey = tModelDetail.getTModel().get(0).getTModelKey();
		System.out.println("tModel created with key: " + tModelKey);
		tModel.setTModelKey(tModelKey);
		     
		//set CategoryBag
		CategoryBag catBag = new CategoryBag();
		List<KeyedReference> krlist = catBag.getKeyedReference();     
		KeyedReference kr = new KeyedReference();
		kr.setKeyName("uuid-org:types");
		kr.setKeyValue("wsdlSpec");
		kr.setTModelKey(tModelKey);
		krlist.add(kr);
		               
		tModel.setCategoryBag(catBag);

		//set the IdentifierBag
		IdentifierBag idBag = new IdentifierBag();
		List<KeyedReference> idkeylist = idBag.getKeyedReference();
		KeyedReference idKey = new KeyedReference();
		idKey.setKeyName(serviceName);
		idKey.setKeyValue(serviceDescription);
		idKey.setTModelKey(tModelKey);
		idkeylist.add(idKey);
		     
		tModel.setIdentifierBag(idBag);   
		     
		//udpate the tModel to the "save" structure, using our publisher's authentication info and saving away.
		SaveTModel updateTModel = new SaveTModel();
		updateTModel.getTModel().addAll(tModelList);
		updateTModel.setAuthInfo(authinfo);
		tModelDetail = this.myPublicationPortType.saveTModel(updateTModel);
		    
		tModelKey = tModelDetail.getTModel().get(0).getTModelKey();
		System.out.println("tModel key: " + tModelKey);   
		      
		return tModelDetail;
	}
	
	private AccessPoint createAccessPoint(String url) {
        AccessPoint accessPoint = new AccessPoint();
        accessPoint.setUseType("http");
        accessPoint.setValue(url);     
        return accessPoint;
    }
}
